home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Delphi Magazine Collection 2001
/
Delphi Magazine Collection 20001 (2001).iso
/
DISKS
/
ISSUE23
/
PASTOWEB
/
NewParse.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1997-05-09
|
9KB
|
389 lines
unit NewParse;
interface
uses
Classes, SysUtils, Consts;
const
toComment = Char(5);
type
TNewParser = class(TObject)
private
FStream: TStream;
FOrigin: Longint;
FBuffer: PChar;
FBufPtr: PChar;
FBufEnd: PChar;
FSourcePtr: PChar;
FSourceEnd: PChar;
FTokenPtr: PChar;
FStringPtr: PChar;
FSourceLine: Integer;
FSaveChar: Char;
FToken: Char;
procedure ReadBuffer;
procedure SkipBlanks;
public
constructor Create(Stream: TStream);
destructor Destroy; override;
procedure CheckToken(T: Char);
procedure CheckTokenSymbol(const S: string);
procedure Error(const Ident: string);
procedure ErrorFmt(const Ident: string; const Args: array of const);
procedure ErrorStr(const Message: string);
procedure HexToBinary(Stream: TStream);
function NextToken: Char;
function SourcePos: Longint;
function TokenComponentIdent: String;
function TokenFloat: Extended;
function TokenInt: Longint;
function TokenString: string;
function TokenSymbolIs(const S: string): Boolean;
property SourceLine: Integer read FSourceLine;
property Token: Char read FToken;
end;
implementation
const
ParseBufSize = 4096;
procedure BinToHex(Buffer, Text: PChar; BufSize: Integer); assembler;
asm
PUSH ESI
PUSH EDI
MOV ESI,EAX
MOV EDI,EDX
MOV EDX,0
JMP @@1
@@0: DB '0123456789ABCDEF'
@@1: LODSB
MOV DL,AL
AND DL,0FH
MOV AH,@@0.Byte[EDX]
MOV DL,AL
SHR DL,4
MOV AL,@@0.Byte[EDX]
STOSW
DEC ECX
JNE @@1
POP EDI
POP ESI
end;
function HexToBin(Text, Buffer: PChar; BufSize: Integer): Integer; assembler;
asm
PUSH ESI
PUSH EDI
PUSH EBX
MOV ESI,EAX
MOV EDI,EDX
MOV EBX,EDX
MOV EDX,0
JMP @@1
@@0: DB 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
DB -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
DB -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
DB -1,10,11,12,13,14,15
@@1: LODSW
CMP AL,'0'
JB @@2
CMP AL,'f'
JA @@2
MOV DL,AL
MOV AL,@@0.Byte[EDX-'0']
CMP AL,-1
JE @@2
SHL AL,4
CMP AH,'0'
JB @@2
CMP AH,'f'
JA @@2
MOV DL,AH
MOV AH,@@0.Byte[EDX-'0']
CMP AH,-1
JE @@2
OR AL,AH
STOSB
DEC ECX
JNE @@1
@@2: MOV EAX,EDI
SUB EAX,EBX
POP EBX
POP EDI
POP ESI
end;
constructor TNewParser.Create(Stream: TStream);
begin
FStream := Stream;
GetMem(FBuffer, ParseBufSize);
FBuffer[0] := #0;
FBufPtr := FBuffer;
FBufEnd := FBuffer + ParseBufSize;
FSourcePtr := FBuffer;
FSourceEnd := FBuffer;
FTokenPtr := FBuffer;
FSourceLine := 1;
NextToken;
end;
destructor TNewParser.Destroy;
begin
if FBuffer <> nil then
begin
FStream.Seek(Longint(FTokenPtr) - Longint(FBufPtr), 1);
FreeMem(FBuffer, ParseBufSize);
end;
end;
procedure TNewParser.CheckToken(T: Char);
begin
if Token <> T then
case T of
toSymbol:
Error(SIdentifierExpected);
toString:
Error(SStringExpected);
toInteger, toFloat:
Error(SNumberExpected);
else
ErrorFmt(SCharExpected, [T]);
end;
end;
procedure TNewParser.CheckTokenSymbol(const S: string);
begin
if not TokenSymbolIs(S) then ErrorFmt(SSymbolExpected, [S]);
end;
procedure TNewParser.Error(const Ident: string);
begin
ErrorStr(Ident);
end;
procedure TNewParser.ErrorFmt(const Ident: string; const Args: array of const);
begin
ErrorStr(Format(Ident, Args));
end;
procedure TNewParser.ErrorStr(const Message: string);
begin
raise EParserError.CreateFmt(SParseError, [Message, FSourceLine]);
end;
procedure TNewParser.HexToBinary(Stream: TStream);
var
Count: Integer;
Buffer: array[0..255] of Char;
begin
SkipBlanks;
while FSourcePtr^ <> '}' do
begin
Count := HexToBin(FSourcePtr, Buffer, SizeOf(Buffer));
if Count = 0 then Error(SInvalidBinary);
Stream.Write(Buffer, Count);
Inc(FSourcePtr, Count * 2);
SkipBlanks;
end;
NextToken;
end;
function TNewParser.NextToken: Char;
var
I: Integer;
P, S: PChar;
begin
SkipBlanks;
P := FSourcePtr;
FTokenPtr := P;
case P^ of
'A'..'Z', 'a'..'z', '_':
begin
Inc(P);
while P^ in ['A'..'Z', 'a'..'z', '0'..'9', '_'] do Inc(P);
Result := toSymbol;
end;
'#', '''':
begin
S := P;
while True do
case P^ of
'#':
begin
Inc(P);
I := 0;
while P^ in ['0'..'9'] do
begin
I := I * 10 + (Ord(P^) - Ord('0'));
Inc(P);
end;
S^ := Chr(I);
Inc(S);
end;
'''':
begin
Inc(P);
while True do
begin
case P^ of
#0, #10, #13:
Error(SInvalidString);
'''':
begin
Inc(P);
if P^ <> '''' then Break;
end;
end;
S^ := P^;
Inc(S);
Inc(P);
end;
end;
else
Break;
end;
FStringPtr := S;
Result := toString;
end;
'$':
begin
Inc(P);
while P^ in ['0'..'9', 'A'..'F', 'a'..'f'] do Inc(P);
Result := toInteger;
end;
'-', '0'..'9':
begin
Inc(P);
while P^ in ['0'..'9'] do Inc(P);
Result := toInteger;
while P^ in ['0'..'9', '.', 'e', 'E', '+', '-'] do
begin
Inc(P);
Result := toFloat;
end;
end;
// new custom code!!!!
'{':
begin
// look for closing brace
while P^ <> '}' do
Inc(P);
// move to the next
Inc(P);
Result := toComment;
end;
else
// updated
if (P^ = '/') and (P^ <> toEOF) and ((P+1)^ = '/') then
begin
// single line comment
while P^ <> #13 do
Inc(P);
Result := toComment;
end
else
begin
Result := P^;
if Result <> toEOF then
Inc(P);
end;
end;
FSourcePtr := P;
FToken := Result;
end;
procedure TNewParser.ReadBuffer;
var
Count: Integer;
begin
Inc(FOrigin, FSourcePtr - FBuffer);
FSourceEnd[0] := FSaveChar;
Count := FBufPtr - FSourcePtr;
if Count <> 0 then Move(FSourcePtr[0], FBuffer[0], Count);
FBufPtr := FBuffer + Count;
Inc(FBufPtr, FStream.Read(FBufPtr[0], FBufEnd - FBufPtr));
FSourcePtr := FBuffer;
FSourceEnd := FBufPtr;
if FSourceEnd = FBufEnd then
begin
FSourceEnd := LineStart(FBuffer, FSourceEnd - 1);
if FSourceEnd = FBuffer then Error(SLineTooLong);
end;
FSaveChar := FSourceEnd[0];
FSourceEnd[0] := #0;
end;
procedure TNewParser.SkipBlanks;
begin
while True do
begin
case FSourcePtr^ of
#0:
begin
ReadBuffer;
if FSourcePtr^ = #0 then Exit;
Continue;
end;
#10:
Inc(FSourceLine);
#33..#255:
Exit;
end;
Inc(FSourcePtr);
end;
end;
function TNewParser.SourcePos: Longint;
begin
Result := FOrigin + (FTokenPtr - FBuffer);
end;
function TNewParser.TokenFloat: Extended;
begin
Result := StrToFloat(TokenString);
end;
function TNewParser.TokenInt: Longint;
begin
Result := StrToInt(TokenString);
end;
function TNewParser.TokenString: string;
var
L: Integer;
begin
if FToken = toString then
L := FStringPtr - FTokenPtr else
L := FSourcePtr - FTokenPtr;
SetString(Result, FTokenPtr, L);
end;
function TNewParser.TokenSymbolIs(const S: string): Boolean;
begin
Result := (Token = toSymbol) and (CompareText(S, TokenString) = 0);
end;
function TNewParser.TokenComponentIdent: String;
var
P: PChar;
begin
CheckToken(toSymbol);
P := FSourcePtr;
while P^ = '.' do
begin
Inc(P);
if not (P^ in ['A'..'Z', 'a'..'z', '_']) then
Error(SIdentifierExpected);
repeat
Inc(P)
until not (P^ in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
end;
FSourcePtr := P;
Result := TokenString;
end;
end.